package com.radar.task.cctv;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.HexUtil;
import com.radar.algorithm.Cacl;
import com.radar.algorithm.DenseLucaskanade;
import com.radar.algorithm.MathCommon;
import com.radar.algorithm.SemiLagrangian;
import com.radar.common.DateConstants;
import com.radar.common.GisConstants;
import com.radar.task.cd.Constants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.filefilter.RegexFileFilter;
import org.bytedeco.javacpp.indexer.Indexer;
import org.bytedeco.opencv.global.opencv_imgcodecs;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.Mat;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Comparator;
import java.util.Date;

@Component
@Slf4j
@Service(value = "ForecastCCTVTask")
public class ForecastCCTVTask {
    //    @Scheduled(cron = "0 0/2 * * * ? ")
    @Scheduled(fixedRate = 50 * 1000)
    public void loopCCTVRadar() {
        FileUtil.loopFiles(Constants.rootPath, new RegexFileFilter("^Z_RADA_C_BABJ_(\\d{14})_P_DOR_ACHN_CREF.png$")).stream().sorted(Comparator.comparingLong(i -> Long.parseLong(i.getName().split("_")[4]))).forEach(i -> process(i));
    }

    public void process(File f) {
        if (FileUtil.exist(f.getAbsolutePath() + ".OK")) {
            return;
        }
        FileUtil.touch(f.getAbsolutePath() + ".OK");
        String date = f.getName().split("_")[4];
        Date obsDate = DateUtil.parse(date, DateConstants.DATE_TIME_FORMAT_YYYYMMDDHHMISS);
//        String processPath = Constants.rootPath + File.separator + DateUtil.format(obsDate, DateConstants.DATE_FORMAT_YYYYMMDD) +
//                File.separator +
//                date + File.separator;
//        if (FileUtil.isDirectory(processPath)) {
//            return;
//        }
        Date preDate = DateUtil.offsetMinute(obsDate, -12);
        String preFile = Constants.rootPath + File.separator + DateUtil.format(preDate, DateConstants.DATE_FORMAT_YYYYMMDD) + File.separator + DateUtil.format(preDate, DateConstants.DATE_TIME_FORMAT_YYYYMMDDHHMISS) + File.separator + "Z_RADA_C_BABJ_" + DateUtil.format(preDate, DateConstants.DATE_TIME_FORMAT_YYYYMMDDHHMISS) + "_P_DOR_ACHN_CREF.png";
//        FileUtil.mkdir(processPath);
//        FileUtil.copy(f, new File(processPath + f.getName()), true);
        String processPath = f.getParentFile().getAbsolutePath() + File.separator;
        if (FileUtil.exist(preFile)) {
            try {
                forecast(preFile, f.getAbsolutePath(), 12, processPath);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void forecast(String preImg, String nextImg, int offset, String output) throws IOException {
        Mat ff1 = opencv_imgcodecs.imread(preImg);
        Mat ff2 = opencv_imgcodecs.imread(nextImg);
        Mat prvs = ff1.clone();
        Mat next = ff1.clone();
        opencv_imgproc.cvtColor(ff1, prvs, opencv_imgproc.COLOR_BGR2GRAY);
        opencv_imgproc.cvtColor(ff2, next, opencv_imgproc.COLOR_BGR2GRAY);

        int step = 4;

        int w = Math.min(prvs.size().get(0), next.size().get(0)) / step;
        int h = Math.min(prvs.size().get(1), next.size().get(1)) / step;

        double[][] pre = new double[h][w];
        double[][] nex = new double[h][w];
        Indexer indexer = prvs.createIndexer();
        Indexer indexer1 = next.createIndexer();

        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                pre[i][j] = indexer.getDouble(i * step, j * step);
                if (pre[i][j] == 255) {
                    pre[i][j] = 0;
                }
                nex[i][j] = indexer1.getDouble(i * step, j * step);
                if (nex[i][j] == 255) {
                    nex[i][j] = 0;
                }
            }
        }
        double[][][] cacl = DenseLucaskanade.cacl(new double[][][]{pre, nex});
        double[][] uu = cacl[0];
        double[][] vv = cacl[1];
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                uu[i][j] = uu[i][j] * (false ? 1.5 : 6.0 / offset);
                vv[i][j] = vv[i][j] * (false ? 1.5 : 6.0 / offset);
            }
        }
        uu = Cacl.nineMedianFilter(uu);
        vv = Cacl.nineMedianFilter(vv);

        double[][] u = new double[uu.length * step][uu[0].length * step];
        double[][] v = new double[uu.length * step][uu[0].length * step];
        for (int i = 0; i < u.length; i++) {
            for (int j = 0; j < u[0].length; j++) {
                u[i][j] = uu[i / step][j / step];
                v[i][j] = vv[i / step][j / step];
            }
        }

        for (int i = 0; i < u.length; i++) {
            for (int j = 0; j < u[0].length; j++) {
                u[i][j] = uu[i / step][j / step];
                v[i][j] = vv[i / step][j / step];
            }
        }
        double[][] decode = getImgData(new File(preImg));
        if (decode.length == u.length && decode[0].length == u[0].length) {

        } else {
            double[][] z = new double[u.length][u[0].length];
            for (int i = 0; i < u.length; i++) {
                for (int j = 0; j < u[0].length; j++) {
                    if (i >= decode.length || j >= decode[0].length) {
                        z[i][j] = GisConstants.UNDEF;
                    } else {
                        z[i][j] = decode[i][j];
                    }
                }
            }
            decode = z;
        }
        SemiLagrangian semiLagrangian = new SemiLagrangian();
        int t = 20;
        float[][][] extrapolate = semiLagrangian.extrapolate(MathCommon.doubleToFloat(decode), MathCommon.doubleToFloat(u), MathCommon.doubleToFloat(v), t);
        for (int i = 0; i < t; i++) {
            BufferedImage bufferedImage;
            for (int j = 0; j < u.length; j++) {
                for (int k = 0; k < u[0].length; k++) {
                    extrapolate[i][j][k] = extrapolate[i][j][k] == 0 || Float.isNaN(extrapolate[i][j][k]) || Float.isInfinite(extrapolate[i][j][k]) ? GisConstants.UNDEF : extrapolate[i][j][k];
                }
            }
            wirteImgData(new File(output + new File(nextImg).getName().replace(".png", "_" + (i + 1) + ".png")), extrapolate[i]);
//            RasterMap rasterMap = new RasterMap(null);
//            bufferedImage = rasterMap.drawSingleRaster(MathCommon.floatToDouble(extrapolate[i]), new Color(0, 0, 0, 0));
//            ImageIO.write(bufferedImage, "png", new File(output + new File(preImg).getName().replace(".png", "_" + (i + 1) + ".png")));
        }
    }

    public static double[][] getImgData(File f) throws IOException {
        BufferedImage read = ImageIO.read(f);
        byte[] bytes = FileUtil.readBytes(f.getAbsolutePath() + ".dat");
        double[][] data = new double[read.getHeight()][read.getWidth()];
//        String[] rgbs = new String[]{"#01A0F6", "#07EBEC", "#6DFA3D", "#00D806", "#019000", "#FFFF00", "#E7BF00", "#FF9000", "#FF0000", "#D60001", "#C00000", "#FF00EF", "#9601B4", "#AD90F0"};
        double[] v = new double[]{5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75};
        int index = 0;
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[0].length; j++) {
                int z = Byte.toUnsignedInt(bytes[index]);
                if (z != 13) {
                    data[i][j] = v[z];
                }
                index ++;
//                for (int z = 0; z < rgbs.length; z++) {
//                    if (HexUtil.decodeColor(rgbs[z]).getRGB() == read.getRGB(j, i)) {
//                        data[i][j] = v[z];
//                        break;
//                    }
//                }
            }
        }
//        data = Cacl.nineMedianFilter(data);
//        data = Cacl.nineMedianFilter(data);
        return data;
    }
    public static void wirteImgData(File f, float[][] data) throws IOException {
        BufferedImage read = new BufferedImage(data[0].length, data.length, 2);;
        String[] rgbs = new String[]{"#01A0F6", "#07EBEC", "#6DFA3D", "#00D806", "#019000", "#FFFF00", "#E7BF00", "#FF9000", "#FF0000", "#D60001", "#C00000", "#FF00EF", "#9601B4", "#AD90F0"};
        double[] v = new double[]{5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75};
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[0].length; j++) {
                for (int z = 0; z < v.length; z++) {
                    if (data[i][j] >= v[z] && data[i][j] < v[z + 1]){
                        read.setRGB(j, i , HexUtil.decodeColor(rgbs[z]).getRGB());
                        break;
                    }
                }
            }
        }
        ImageIO.write(read, "png", f);
    }

    public static void main(String[] args) throws IOException {
        System.out.println(10 * 1e6 == 10000000);
        String file = "D:\\Z_RADA_C_BABJ_20230926054200_P_DOR_ACHN_CREF.png";
        String nextImg = "D:\\Z_RADA_C_BABJ_20230926055400_P_DOR_ACHN_CREF.png";
        forecast(file, nextImg, 12, "D:\\");
    }

}
